package org.hades.corelib.base.view

import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.DialogFragment
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.flow.StateFlow
import org.hades.corelib.R
import org.hades.corelib.base.data.ResultData
import org.hades.corelib.base.data.UIState
import org.hades.corelib.base.exception.ApiException
import org.hades.corelib.base.exception.EmptyException
import org.hades.corelib.base.extend.ShowToast
import org.hades.corelib.base.extend.doLaunch
import org.hades.corelib.base.view.dialog.LoadingDialog
import org.hades.corelib.view.doShow
import org.hades.corelib.base.vm.CoreViewModel

abstract class CoreActivity : AppCompatActivity() {
    open lateinit var mRootView: ViewGroup
    open var vm: CoreViewModel? = null
    open lateinit var mProgress: DialogFragment
    open lateinit var exceptionHandler:CoroutineExceptionHandler

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        initParams(intent?.extras)
        mRootView = initByViewBind(layoutInflater, null)
        setContentView(mRootView)
        onCreateView()
        initProgressDialog()
        vm = onGetViewModel()
        exceptionHandler = initExceptionHandler()
        bindExceptionHandler()
        onCreateViewEvent()
    }


    protected open fun initParams(extras: Bundle?) {}
    abstract fun initByViewBind(layoutInflater: LayoutInflater, viewGroup: ViewGroup?): ViewGroup
    protected open fun onCreateView() {}
    protected open fun onCreateViewEvent() {}
    abstract fun onGetViewModel(): CoreViewModel?

    protected open fun initProgressDialog() {
        mProgress = LoadingDialog()
        mProgress.setStyle(DialogFragment.STYLE_NORMAL, R.style.AppDialog)
        mProgress.isCancelable = false
    }

    protected open fun initExceptionHandler() = CoroutineExceptionHandler { coroutineContext, throwable ->
        handleException(throwable as Exception)
    }


    protected open fun bindExceptionHandler() {
        doLaunch(exceptionHandler) {
            vm?.apply {
                this.uiStateFlow.collect {
                    when (it) {
                        is UIState.OnExecption -> {
                            handleException(it.exception)
                        }
                        is UIState.OnLoading -> {
                            loadStart()
                        }
                        is UIState.OnComplete -> {
                            loadEnd()
                        }
                    }
                }
            }
        }
    }

    protected open fun handleException(exception: Exception) {
        when (exception) {
            is ApiException -> {
                handleApiException(exception)
            }
            is EmptyException -> {
                handleEmptyException(exception)
            }
            else -> {
                showExceptionToast(exception)
            }
        }
        exception.printStackTrace()
    }

    protected open fun handleApiException(e: ApiException) {
        showExceptionToast(e)
    }

    protected open fun handleEmptyException(e: EmptyException) {
        showExceptionToast(e)
    }

    fun showExceptionToast(it: Exception) {
        it.message?.let {
            (javaClass.name + it).ShowToast(baseContext)
        }
    }

    protected open fun loadStart() {
        mProgress.doShow(supportFragmentManager)
    }

    protected open fun loadEnd() {
        mProgress.dismissAllowingStateLoss()
    }

    // 针对密封类包装的数据流进行收集简化，处理异常和loading
    suspend fun <T>StateFlow<ResultData<T>>.doUICollect(block: T.() -> Unit) {
        collect{
            when(it){
                is ResultData.Success ->{ block.invoke(it.data)}
                is ResultData.Loading -> loadStart()
                is ResultData.Error -> { handleException(it.exception)}
            }
        }
    }

}